package com.api.gbhg.luoao.la.util;

import com.alibaba.fastjson.JSON;
import weaver.conn.RecordSet;

import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author 李文军 2021-07-13
 * @company 互联心
 * @desscription 泛微数据库对象实例化工具
 */
public class DaoUtil {
    /**
     * 保存反射字段
     */
    private static Map<String, Field[]> fields=new HashMap<>();


    /**
     * 根据sql查询单个对象
     * @param t 对象类型
     * @param sql 查询语句
     * @param objects 查询参数
     * @param <T> 泛型参数
     * @return 实例对象
     */
    public static <T> T getObjBySql(Class<T> t, String sql, Object... objects){
        RecordSet recordSet = new RecordSet();
        recordSet.executeQuery(sql, objects);
        if (recordSet.next()) {
            T entity = getEntity(t, recordSet);
            return entity;
        }
        return null;
    }



    /**
     * 查询sql，将查询数据根据传入t的字段名称与sql字段名称映射，进行对象转化
     *
     * @param t       数据库对象模型
     * @param sql     查询sql
     * @param objects sql参数
     * @param <T>     数据库对象模型类型
     * @return 返回list集合
     */
    public static <T> List<T> getListBySql(Class<T> t, String sql, Object... objects) {
        RecordSet recordSet = new RecordSet();
        recordSet.executeQuery(sql, objects);
        List<T> list = new ArrayList<>();
        while (recordSet.next()) {
            T entity = getEntity(t, recordSet);
            list.add(entity);
        }
        return list;
    }

    /**
     * 查询数据库，返回单条数据map
     *
     * @param sql     查询sql
     * @param objects 查询参数
     * @return map数据
     */
    public static Map<String, Object> getMapBySql(String sql, Object... objects) {
        RecordSet recordSet = new RecordSet();
        recordSet.executeQuery(sql, objects);
        recordSet.writeLog("查询sql："+sql+"   "+ JSON.toJSONString(objects));
        Map<String, Object> resMap = new HashMap<>();
        try {
            String[] cols = recordSet.getColumnName();
            Vector vector = recordSet.getArray();
            if (vector.size() > 0) {
                Object[] obj = (Object[]) vector.get(0);
                for (int i = 0; i < cols.length; i++) {
                    String cName = cols[i];
                    Object val = obj[i];
                    resMap.put(cName, val);
                }
            }
        }catch (Exception ex){

        }
        return resMap;
    }


    /**
     * 查询数据库，返回listmap
     *
     * @param sql
     * @param objects
     * @return ListMap
     */
    public static List<Map<String, Object>> getListMapBySql(String sql, Object... objects) {
        RecordSet recordSet = new RecordSet();
        recordSet.executeQuery(sql, objects);
        List<Map<String, Object>> resList = new ArrayList<>();
        String[] cols = recordSet.getColumnName();
        Vector vector = recordSet.getArray();
        if (vector.size() > 0) {
            for (Object item : vector) {
                Map<String, Object> resMap = new HashMap<>();
                Object[] obj = (Object[]) item;
                for (int i = 0; i < cols.length; i++) {
                    String cName = cols[i];
                    Object val = obj[i];
                    resMap.put(cName, val);
                }
                resList.add(resMap);
            }
        }
        return resList;
    }

    /**
     * 使用map插入数据库
     * @param map map数据
     * @param tableName 对应的数据库表
     * @return 是否成功
     */
    public static boolean insertByMap(Map<String, Object> map, String tableName) {
        try {
            StringBuilder sb = new StringBuilder();
            sb.append("insert into ");
            sb.append(tableName);
            sb.append(genInsertFieldSql(Arrays.asList(map.keySet().toArray())));
            sb.append("values");
            sb.append(genQM(map.keySet().size()));
            RecordSet recordSet=new RecordSet();
            return recordSet.executeUpdate(sb.toString(),map.values().toArray());
        }catch (Exception ex){
            return false;
        }
    }

    /**
     * 使用对象插入数据库
     * @param obj 对象
     * @param tableName 数据库表名
     * @param <T> 对象类型
     * @return
     */
    public  static <T> boolean insertByObject(T obj, String tableName){
        Field[] field = null;
        Class<T> cls= (Class<T>) obj.getClass();
        if (!fields.containsKey(cls)) {
            fields.put(cls.getName(), cls.getDeclaredFields());
        }
        field = fields.get(cls.getName());
        List<Object> fields= Arrays.stream(field).map(r->r.getName()).collect(Collectors.toList());

        List<Object> fieldsVal=Arrays.stream(field).map(r-> {
            try {
                r.setAccessible(true);
                return r.get(obj);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            return null;
        }).collect(Collectors.toList());

        StringBuilder sb = new StringBuilder();
        sb.append("insert into ");
        sb.append(tableName);
        sb.append(genInsertFieldSql(fields));
        sb.append("values");
        sb.append(genQM(fields.size()));
        RecordSet recordSet=new RecordSet();
        return recordSet.executeUpdate(sb.toString(),fieldsVal);
    }


    /**
     * 根据map更新记录
     * @param map map数据
     * @param tableName 数据库表名
     * @param idName 主键名称
     * @return 是否成功
     */
    public static boolean updateByMap(Map<String, Object> map, String tableName,String idName){
        try {
            StringBuilder sb = new StringBuilder();
            sb.append("update ");
            sb.append(tableName);
            sb.append(" set ");
            List<Object> fields= Arrays.asList(map.keySet().toArray()).stream().filter(r->!r.equals(idName)).collect(Collectors.toList());
            List<Object> values=fields.stream().map(r->map.get(r)).collect(Collectors.toList());
            values.add(map.get(idName));
            sb.append(genUpdateFieldSql(fields));
            sb.append(" where ");
            sb.append(idName);
            sb.append("=?");
            RecordSet recordSet=new RecordSet();
            recordSet.executeUpdate(sb.toString(),values);
        }catch (Exception ex){
            return false;
        }
        return true;
    }


    public static <T> boolean updateByObj(T obj,String tableName,String idName) {
        Field[] field = null;
        Class<T> cls= (Class<T>) obj.getClass();
        if (!fields.containsKey(cls)) {
            fields.put(cls.getName(), cls.getDeclaredFields());
        }
        field = fields.get(cls.getName());
        List<Object> updateFields= Arrays.stream(field).map(r->r.getName()).filter(r->!r.equals(idName)).collect(Collectors.toList());
        List<Object> values=Arrays.stream(field).filter(r->!r.getName().equals(idName)).map(r-> {
            try {
                r.setAccessible(true);
                return r.get(obj);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            return null;
        }).collect(Collectors.toList());
        Field fId= Arrays.stream(field).filter(r->r.getName().equals(idName)).findFirst().get();
        fId.setAccessible(true);
        try {
            values.add( fId.get(obj));
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        StringBuilder sb = new StringBuilder();
        sb.append("update ");
        sb.append(tableName);
        sb.append(" set ");
        sb.append(genUpdateFieldSql(updateFields));
        sb.append(" where ");
        sb.append(idName);
        sb.append("=?");
        RecordSet recordSet=new RecordSet();
        return recordSet.executeUpdate(sb.toString(),values);
    }

    /**
     * 生成 AND key=value  sql片段 ，当value为空或者null 返回空字符串
     *
     * @param key
     * @param value
     * @return
     */
    public static String getAndSql(String key, String value) {
        if (value != null && !value.isEmpty()) {
            return " AND " + key + "='" + value + "' ";
        }
        return "";
    }

    /**
     * 生成 AND key like value  sql片段 ，当value为空或者null 返回空字符串
     *
     * @param key
     * @param value
     * @return
     */
    public static String getAndLikeSql(String key, String value) {
        if (value != null && !value.isEmpty()) {
            return " AND " + key + " like '%" + value + "%' ";
        }
        return "";
    }


    /**
     * 产生指定长度的问号
     * @param len
     * @return
     */
    public static String genQM(int len){
        StringBuilder sb=new StringBuilder();
        sb.append("(");
        for(int i=0;i<len;i++){
            sb.append("?");
            if(i<len-1){
                sb.append(",");
            }
        }
        sb.append(")");
        return sb.toString();
    }

    /**
     * 产生插入语句
     * @param cols
     * @return
     */
    public static String genInsertFieldSql(List<Object> cols) {
        StringBuilder sb = new StringBuilder();
        sb.append("(");
        int i = cols.size();
        int flag = 0;
        for (Object v : cols) {
            flag++;
            sb.append("\"");
            sb.append(v.toString().toUpperCase());
            sb.append("\"");
            if (flag < i) {
                sb.append(',');
            }
        }
        sb.append(")");
        return sb.toString();
    }

    /**
     * 产生指定长度的更新语句
     * @param cols
     * @return
     */
    public static String genUpdateFieldSql(List<Object> cols) {
        StringBuilder sb = new StringBuilder();
        int s = cols.size();
        int flag = 0;
        for(Object key:cols){
            flag++;
            sb.append(key);
            sb.append("=?");
            if(flag<s){
                sb.append(",");
            }
        }
        return sb.toString();
    }

    /**
     * 数据库对象转实体类
     * @param t 实体类型
     * @param recordSet 数据库访问模型
     * @param <T> 泛型参数
     * @return
     */
    private static <T> T getEntity(Class<T> t, RecordSet recordSet) {
        try {
            T tentity = t.newInstance();
            String className = t.getName();
            Field[] field = null;
            if (!fields.containsKey(className)) {
                fields.put(className, t.getDeclaredFields());
            }
            field = fields.get(className);
            for (Field f : field) {
                f.setAccessible(true);
                if (f.getType().equals(Integer.class)) {
                    f.set(tentity, recordSet.getInt(f.getName()));
                } else if (f.getType().equals(int.class)) {
                    f.set(tentity, recordSet.getInt(f.getName()));
                } else if (f.getType().equals(Date.class)) {
                    f.set(tentity, recordSet.getDate(f.getName()));
                } else if (f.getType().equals(Boolean.class)) {
                    f.set(tentity, recordSet.getBoolean(f.getName()));
                } else if (f.getType().equals(Double.class)) {
                    f.set(tentity, recordSet.getDouble(f.getName()));
                } else if (f.getType().equals(Float.class)) {
                    f.set(tentity, recordSet.getFloat(f.getName()));
                } else {
                    f.set(tentity, recordSet.getString(f.getName()));
                }
            }
            return tentity;
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }







}
